'''非数值型数据预处理'''

#导入库
from sklearn.svm import SVC
from apart import df_isn, df_non
from sklearn.feature_selection import RFE
from sklearn.feature_selection import chi2
from pypinyin import pinyin,lazy_pinyin,Style
from sklearn.feature_selection import SelectKBest
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import VarianceThreshold
import category_encoders as ce
import pandas as pd
import numpy as np 
import pypinyin
import difflib
import random
from category_encoders import LeaveOneOutEncoder

## 类似宏定义
#——小于该航班号长度的删除
FLIGHT_NUM_LEN = 4

## 列表类
#——缺失值形式集合
Missing = ['***','NULL'] 
#——‘U’为无效值
U_feature = ['gender','marital_stat']
#——序号编码
serial_encode =  ['age']
#——不处理的特征
not_deal = ['pax_name', 'pax_passport']
#——航班
flight_feature = ['pref_line_m3_1', 'pref_line_m3_2', 'pref_line_m3_3', 'pref_line_m3_4', 'pref_line_m3_5', 'pref_line_m6_1', 'pref_line_m6_2', 'pref_line_m6_3', 'pref_line_m6_4', 'pref_line_m6_5', 'pref_line_y1_1', 'pref_line_y1_2', 'pref_line_y1_3', 'pref_line_y1_4', 'pref_line_y1_5', 'pref_line_y2_1', 'pref_line_y2_2', 'pref_line_y2_3', 'pref_line_y2_4', 'pref_line_y2_5', 'pref_line_y3_1', 'pref_line_y3_2', 'pref_line_y3_3', 'pref_line_y3_4', 'pref_line_y3_5', 'pref_orig_city_y2', 'pref_orig_city_y3']
#——city_name特征替换字典
city_name_replace_dict = {'ARCADIA': '美国路易斯安那州', 'ASAKURAGUN': '日本福冈县', 'ATLANTIS': '0', 'Amherst': '美国马萨诸赛州', 'BANGKOK': '泰国曼谷', 'BROOKLYN': '美国纽约州', 'Bangkok': '泰国曼谷', 'Beijing': '中国北京', 'Bexley North': '澳大利亚新南威尔士州', 'Brooklyn': '美国纽约州', 'Brownville': '美国德克萨斯州', 'Burbank': '美国加利福尼亚州', 'CARINGBAH SOUTH': '澳大利亚新南威尔士州', 'CARLINGFORD': '澳大利亚新南威尔士州', 'CHANGZHOU': '中国江苏', 'CHINO HILLS': '美国加利福尼亚州', 'COVINA': '美国加利福尼亚州', 'Campsie': '澳大利亚新南威尔士州', 'Castle Hill': '美国马萨诸赛州', 'Chesterbrook': '美国宾夕法尼亚州', 'Costa Mesa': '美国加利福尼亚州', 'Cypress': '美国加利福尼亚州', 'DIAMOND BAR': '美国加利福尼亚州', 'Diamond Bar': '美国加利福尼亚州', 'Englewood': '美国新泽西州', 'Exton': '美国宾夕法尼亚州', 'FARMINGDALE': '美国纽约州', 'FLUSHING': '美国纽约州', 'FRESH MEADOWS': '美国纽约州', 'Flushing': '美国纽约州', 'Gainesville': '美国佛罗里达州', 'Guadalajara': '墨西哥哈利斯科州', 'HIROSHIMA': '日本广岛县', 'HORNSBY': '澳大利亚新南威尔士州', 'HOUSTON': '美国德克萨斯州', 'HUNTERS HILL': '澳大利亚新南威尔士州', 'HURSTVILLE': '澳大利亚新南威尔士州', 'Hong Kong': '中国香港', 'INGLEBURN': '澳大利亚新南威尔士州', 'IRVINE': '美国加利福尼亚州', 'Irvine': '美国加利福尼亚州', 'JOHOR BAHRU': '马来西亚柔佛州', 'Jersery City': '美国新泽西州', 'KASUGASHI': '日本福冈县', 'KIRRAWEE': '澳大利亚新南威尔士州', 'LOS  ANGELES': '美国加利福尼亚州', 'LOS ANGELES': '美国加利福尼亚州', 'Loma Linda': '美国加利福尼亚州', 'Los Angeles': '美国加利福尼亚州', 'MASCOT': '澳大利亚新南威尔士州', 'Marsfield，NSW': '澳大利亚新南威尔士州', 'Middle Island': '美国康涅狄格州', 'Molndal': '瑞典西约塔兰省', 'Monroe': '美国密歇根州', 'NEW YORK': '美国纽约州', 'NEWPORT BEACH': '美国加利福尼亚州', 'NISHITOKYO-SHI': '日本东京', 'NSW': '澳大利亚新南威尔士州', 'NY': '中国河南', 'New Haven': '美国康涅狄格州', 'New York': '美国纽约州', 'Newcastle': '澳大利亚新南威尔士州', 'North Rocks': '澳大利亚新南威尔士州', 'OKAYAMA-CITY': '日本冈山县', 'Oak Park': '美国伊利诺斯州', 'Oakland gardens': '美国加利福尼亚州', 'Old Bethpage': '美国纽约州', 'Pasig City': '菲律宾黎刹省', 'Philadelphia': '美国宾夕法尼亚州', 'Plymouth': '英国英格兰', 'Port St Lucie': '美国佛罗里达州', 'Pratumwan': '0', 'RIVERWOOD': '澳大利亚新南威尔士州', 'ROWLAND HEIGHTS': '美国加利福尼亚州', 'RUNAWAY BAY': '澳大利亚昆士兰州', 'Redlands': '美国加利福尼亚州', 'Regents Park': '澳大利亚新南威尔士州', 'Rochester': '美国纽约州', 'Ryde': '澳大利亚新南威尔士州', 'SANDY BAY': '澳大利亚塔斯马尼亚州', 'SHANGHAI': '中国上海', 'SINGAPORE': '新加坡', 'SOUTH SETAUKET': '美国纽约州', 'STRATHFIELD': '澳大利亚新南威尔士州', 'SYDNEY': '澳大利亚新南威尔士州', 'San Diego, CA': '美国加利福尼亚州', 'Santa Fe Springs': '美国加利福尼亚州', 'Seoul': '韩国首尔', 'Shanghai': '中国上海', 'Singapore': '新加坡', 'Smithfield': '美国弗吉尼亚州', 'St Peters': '俄罗斯列宁格勒州', 'Sugar Land': '美国德克萨斯州', 'Sydney': '澳大利亚新南威尔士州', 'Sydney, Australia': '澳大利亚新南威尔士州', 'TEMPLE CITY': '美国加利福尼亚州', 'TORRANCE': '美国加利福尼亚州', 'Taipei': '中国台湾', 'The Rocks': '澳大利亚新南威尔士州', 'Truganina': '澳大利亚维多利亚州', 'Tustin': '美国加利福尼亚州', 'US': '0', 'WATERFORD': '英国英格兰', 'WENTWORTH POINT': '澳大利亚新南威尔士州', 'WEST COVINA': '美国加利福尼亚州', 'WUXI': '中国江苏', 'Westport': '美国康涅狄格州', 'Woburn': '美国马萨诸赛州', 'Wonju-si': '韩国江原道', 'Yorktown Heights': '美国弗吉尼亚州', 'bogota': '哥伦比亚昆迪纳马卡省', 'casula': '澳大利亚新南威尔士州', 'corona': '美国加利福尼亚州', 'df': '中国河南', 'fairfield': '美国加利福尼亚州', 'flushing': '美国纽约州', 'forest hills': '美国纽约', 'guangzhou': '中国广东', 'hurstville': '澳大利亚新南威尔士州', 'kellyville': '澳大利亚新南威尔士州', 'murphy': '美国爱达荷州', 'nan': '0', 'new york': '美国纽约州', 'san diego': '美国加利福尼亚州', 'shanghai': '中国上海', 'sydney': '澳大利亚新南威尔士州', 'torrance': '美国加利福尼亚州', 'yixing': '中国江苏', 'zhuhai': '中国广东', '上海': '中国上海', '上海普陀区': '中国上海', '中壢區': '中国台湾', '临沂': '中国山东', '丹东': '中国辽宁', '义乌': '中国浙江', '乐山': '中国四川', '仙桃': '中国湖北', '伊春': '中国黑龙江', '余姚': '中国浙江', '信阳': '中国河南', '兰州': '中国甘肃', '北京': '中国北京', '南京': '中国江苏', '南昌': '中国江西', '南通': '中国江苏', '卢湾区': '中国上海', '原阳县': '中国河南', '台中': '中国台湾', '台北': '中国台湾', '台州': '中国江苏', '合肥': '中国安徽', '吉林': '中国吉林', '启东': '中国江苏', '吴江': '中国江苏', '哈尔滨': '中国黑龙江', '唐山': '中国河北', '嘉兴': '中国浙江', '基隆': '中国台湾', '大安區': '中国台湾', '大庆': '中国黑龙江', '大连': '中国辽宁', '大阪府大阪': '日本大阪府', '天津': '中国天津', '太原': '中国山西', '太原市万柏林区': '中国山西', '奉化': '中国浙江', '如东': '中国江苏', '如皋': '中国江苏', '宁德': '中国福建', '宁波': '中国浙江', '安庆': '中国安徽', '安徽': '中国安徽', '宜兴': '中国江苏', '宜昌': '中国湖北', '宜蘭': '中国台湾', '宝山区': '中国上海', '宣城': '中国安徽', '山阴县': '中国山西', '崇文区': '中国北京', '川崎': '日本神奈川县', '常州': '中国江苏', '常熟': '中国江苏', '广州': '中国广东', '张家港': '中国江苏', '待确认': '0', '徐汇': '中国上海', '徐汇区': '中国上海', '悉尼': '澳大利亚新南威尔士州', '慈溪': '中国浙江', '成都': '中国四川', '扬州': '中国江苏', '承德': '中国河北', '抚顺': '中国辽宁', '新北': '中国台湾', '新北市新店區': '中国台湾', '新泰': '中国山东', '无锡': '中国江苏', '日照': '中国山东', '旧金山': '美国加利福尼亚州', '昆明': '中国云南', '昭通': '中国云南', '普陀区': '中国上海', '杨浦区': '中国上海', '杭州': '中国浙江', '松江区': '中国上海', '枝江': '中国湖北', '柳州': '中国广西', '桂林': '中国广西', '桃園': '中国台湾', '武汉': '中国湖北', '江阴': '中国江苏', '汪清县': '中国吉林', '沈阳': '中国辽宁', '洛杉矶': '美国加利福尼亚州', '洛阳': '中国河南', '济南': '中国山东', '浦东新区': '中国上海', '海宁': '中国浙江', '海淀区': '中国北京', '淮北': '中国安徽', '淮安市淮阴区': '中国江苏', '深圳': '中国广东', '温岭': '中国浙江', '温州': '中国浙江', '湖州': '中国浙江', '烟台': '中国山东', '焦作': '中国河南', '甘肃省': '中国甘肃', '盐城': '中国江苏', '盘锦': '中国辽宁', '石家庄': '中国河北', '石景山区': '中国北京', '福州': '中国福建', '纽约': '美国纽约州', '绍兴': '中国浙江', '羅東鎮': '中国福建', '臺北': '中国台湾', '舟山': '中国浙江', '芜湖': '中国安徽', '花果山': '中国江苏', '苏州': '中国江苏', '虹口区': '中国上海', '衡阳': '中国湖南', '西安': '中国陕西', '西安市长安区': '中国陕西', '贵阳': '中国贵州', '赣州': '中国江西', '赤峰': '中国内蒙古', '郑州': '中国河南', '金华': '中国浙江', '铜川': '中国陕西', '铜陵': '中国安徽', '银川': '中国宁夏', '长乐': '中国福建', '长宁区': '中国上海', '长春': '中国吉林', '长沙': '中国湖南', '闵行区': '中国上海', '随州': '中国湖北', '青岛': '中国山东', '静安区': '中国上海', '鞍山': '中国安徽', '高雄': '中国台湾', '黑龙江省': '中国黑龙江'}
#——provinc_name特征替换字典
province_name_replace_dict = {'AH': '中国安徽', 'BJ': '中国北京', 'CA': '美国加利福尼亚州', 'CALIFONIA': '美国加利福尼亚州', 'CALIFORNIA': '美国加利福尼亚州', 'CONNECTICUT': '美国康涅狄格州', 'CQ': '中国重庆', 'California': '美国加利福尼亚州', 'Connecticut': '美国康涅狄格州', 'Davao del Sur': '菲律宾达沃省', 'FJ': '中国福建', 'GD': '中国广东', 'GS': '中国甘肃', 'GX': '中国台湾', 'Gangwon-do': '韩国江原道', 'HA': '中国河南', 'HE': '中国河北', 'HJ': '中国河北', 'HK': '中国海南', 'HS': '中国河北', 'Harrison': '美国艾奥瓦州', 'Hong Kong': '中国香港', 'JL': '中国吉林', 'JS': '中国江苏', 'JX': '中国江西', 'Jalisco': '墨西哥哈利斯科州', 'LN': '中国辽宁', 'MARYLAND': '美国马里兰州', 'Michigan': '美国密歇根州', 'NEW SOUTH WALES': '澳大利亚新南威尔士州', 'NEW YORK': '美国纽约州', 'NEWYORK': '美国纽约州', 'NJ': '中国江苏', 'NM': '中国内蒙古', 'NSW': '澳大利亚新南威尔士州', 'NY': '中国河南', 'New York': '美国纽约州', 'NewYork': '美国纽约州', 'OHIO': '美国俄亥俄州', 'OKAYAMA': '日本冈山县', 'OSAKA': '日本大阪府', 'QLD': '澳大利亚昆士兰州', 'Rizal': '菲律宾黎刹省', 'SC': '中国四川', 'SD': '美国南达科他州', 'SH': '中国上海', 'SS': '意大利萨萨里省', 'SX': '中国陕西', 'Singapore': '新加坡', 'TJ': '中国天津', 'TW': '中国台湾', 'UT': '美国犹他州', 'Washington': '美国华盛顿州', 'XG': '中国香港', 'YN': '中国云南', 'ZJ': '中国浙江', 'act': '澳大利亚首都领地', 'ca': '美国加利福尼亚州', 'california': '美国加利福尼亚州', 'connecticut': '美国康涅狄格州', 'new york': '美国纽约州', 'nsw': '澳大利亚新南威尔士州', 'sh': '中国上海', 'taiwan': '中国台湾', 'texas': '美国德克萨斯州', 'us': '0', '上海': '中国上海', '上海市': '中国上海', '加利福尼亚': '美国加利福尼亚州', '北京市': '中国北京', '台北市': '中国台湾', '台灣': '中国台湾', '台灣省': '中国台湾', '四川省': '中国四川', '安徽': '中国安徽', '山东省': '中国山东', '新北市': '中国台湾', '桃園區': '中国台湾', '桃園市': '中国台湾', '浙江': '中国浙江', '臺灣': '中国台湾', '黑龙江省': '中国黑龙江'}
#——非数值型却包含纯数字
num_include_list = ['pref_aircraft_m3_1', 'pref_aircraft_m3_2', 'pref_aircraft_m3_3', 'pref_aircraft_m3_4', 'pref_aircraft_m3_5', 'pref_aircraft_m6_1', 'pref_aircraft_m6_2', 'pref_aircraft_m6_3', 'pref_aircraft_m6_4', 'pref_aircraft_m6_5', 'pref_aircraft_y1_1', 'pref_aircraft_y1_2', 'pref_aircraft_y1_3', 'pref_aircraft_y1_4', 'pref_aircraft_y1_5', 'pref_aircraft_y2_1', 'pref_aircraft_y2_2', 'pref_aircraft_y2_3', 'pref_aircraft_y2_4', 'pref_aircraft_y2_5', 'pref_aircraft_y3_1', 'pref_aircraft_y3_2', 'pref_aircraft_y3_3', 'pref_aircraft_y3_4', 'pref_aircraft_y3_5']

## 数据读取
datafile = '3_result.csv'
resultfile_non_encoded = 'non_encoded.csv'
resultfile_target_encoded = 'target_encoded.csv'
resultfile_generalized_encoded = 'generalized_encoded.csv'
resultfile_target_encoded_only = 'target_encoded_only.csv'
resultfile_generalized_encoded_only = 'generalized_encoded_only.csv'
df = pd.read_csv(datafile, low_memory=False, encoding='utf_8_sig')
data = df

## 多样缺失值形式统一为0
for u in df_non:
    categories = list(data[u].unique())
    if 0 in categories:
        categories.remove(0)
    for cat in categories:
        #为已知的无效值 或 不在num_include_list中却含有除0以外的纯数字
        if cat in Missing or (num_include_list.count(cat)==0 and str(cat).isdigit()): #逻辑与或（and、or），按位与或异或（&、|、^）
            data[u] = data[u].replace(str(cat).split('-'), [0])
#——U->0
for u in U_feature:
    data[u] = data[u].replace(['U'], [0])
#——航班处理
for flight in flight_feature:
    categories = list(data[flight].unique())
    for cat in categories:
        # 长度小于FLIGHT_NUM_LEN 且 不包含‘-’的为无效值
        if len(str(cat))<=FLIGHT_NUM_LEN and '-' not in str(cat):
            data[flight] = data[flight].replace(cat, 0)
            
## city_name 处理（包含于province合并）
#——city_name
keys = list(city_name_replace_dict.keys())
values = list(city_name_replace_dict.values())
categories = list(data['city_name'].unique())
if 0 in categories:
    categories.remove(0)
for cat in categories:
    cat_s = str(cat)
    # 长度为1的视为无效值
    if len(cat_s)<=1:
        data['city_name'] = data['city_name'].replace(cat, 0)
    # 去除结尾的'市'
    if cat_s.endswith('市'):
        index = cat_s.rindex('市')
        cat_replaced = cat_s[0:index] 
        data['city_name'] = data['city_name'].replace(cat, cat_replaced)
data['city_name'] = data['city_name'].replace(keys, values)
#——province_name
keys = list(province_name_replace_dict.keys())
values = list(province_name_replace_dict.values())
categories = list(data['province_name'].unique())
if 0 in categories:
    categories.remove(0)
for cat in categories:
    cat_s = str(cat)
    # 长度为1的视为无效值
    if len(cat_s)<=1:
        data['city_name'] = data['city_name'].replace(cat, 0)
data['province_name'] = data['province_name'].replace(keys, values)
#——合并
for i in data['city_name']:
    if i == 0 and data['province_name'][i] != 0:
        data['city_name'][i] = data['province_name'][i]
#——删除province_name
del data['province_name']
df_non.remove('province_name')  

'''
## 缺失值处理 -------- 概率填充     
for u in df_non:
    print(u,"---:")
    count_0 = list(df[u]).count(0)
    len_u = len(list(df[u]))
    missing_rate = count_0/len_u
    if missing_rate > MISSING_RATE_MAX:
        categories = list(data[u].unique())
        categories.remove(0)
        index = [i for i, x in enumerate(data[u]) if x == 0]  
        rate_max = 0
        cat_max = categories[0]
        for cat in categories:
            rate = (list(data[u]).count(cat))/(len_u-count_0)
            print(cat,':',rate)
            if rate > rate_max:
                rate_max = rate
                cat_max = cat
            print(len(index), int(count_0*rate))
            random_index = random.sample(index, int(count_0*rate))
            data[u] = pd.DataFrame(np.delete(np.array(data[u]),random_index,0))
            data[u] = pd.DataFrame(np.insert(np.array(data[u]),random_index,cat,0))
            index = list(set(index) - set(random_index))
        if len(index) != 0:
            data[u] = pd.DataFrame(np.delete(np.array(data[u]),index,axis=0))
            data[u] = pd.DataFrame(np.insert(np.array(data[u]),index,cat_max,0))
'''

## 非数值化保存
data.to_csv(resultfile_non_encoded, sep=',', header=True, index=False, encoding='utf_8_sig')  

## 数值化处理 
df_non = list((set(df_non) - set(serial_encode)).difference(set(not_deal)))
   
data_non = pd.DataFrame(df[df_non])   #创建数据框

#——二进制编码
#encoder = ce.BinaryEncoder(cols = df_non).fit(data_non)  #创建用于二进制编码的对象
#data_non = encoder.transform(data_non) #适合和转换数据 
#——目标编码
encoder = ce.target_encoder.TargetEncoder(cols = df_non).fit(data_non, data['emd_lable2'])  #创建用于目标编码的对象
data_non_target = encoder.transform(data_non, data['emd_lable2']) #适合和转换数据 
#——广义线性混合编码
encoder = ce.glmm.GLMMEncoder(cols = df_non).fit(data_non, data['emd_lable2'])  #创建用于广义线性混合编码的对象
data_non_generalized = encoder.transform(data_non, data['emd_lable2']) #适合和转换数据 
#print('data_non:\n', data_non)

#——序号编码
data_serial = pd.DataFrame(df[serial_encode])
for se in serial_encode:
    categories = list(data[se].unique()) 
    categories.sort()
    data_serial[se] = data_serial[se].replace(categories, range(0,len(categories)))
data_serial = pd.DataFrame(data_serial)
#print('data_serial:\n', data_serial)

##合并   
data_isn = pd.DataFrame(df[df_isn])
#data_encoded = pd.concat([data_serial, data_non, data_isn], axis=1, join='outer', ignore_index=False) 
data_target_encoded = pd.concat([data_serial, data_non_target, data_isn], axis=1, join='outer', ignore_index=False) 
data_generalized_encoded = pd.concat([data_serial, data_non_generalized, data_isn], axis=1, join='outer', ignore_index=False) 
data_target_encoded_only = pd.concat([data_serial, data_non_target], axis=1, join='outer', ignore_index=False) 
data_generalized_encoded_only = pd.concat([data_serial, data_non_generalized], axis=1, join='outer', ignore_index=False) 

data_target_encoded.to_csv(resultfile_target_encoded, sep=',', header=True, index=False, encoding='utf_8_sig')
data_generalized_encoded.to_csv(resultfile_generalized_encoded, sep=',', header=True, index=False, encoding='utf_8_sig')
data_target_encoded_only.to_csv(resultfile_target_encoded_only, sep=',', header=True, index=False, encoding='utf_8_sig')
data_generalized_encoded_only.to_csv(resultfile_generalized_encoded_only, sep=',', header=True, index=False, encoding='utf_8_sig')

'''
axis=0表示上下合并，1表示左右合并;
ignore_index=True表示忽略原来的索引;
join为‘inner’时 会裁剪吊互相之间没有的数据，
join为‘outer’时 会用NaN值来填充相互之间没有的数据。
'''
## 保存与输出
#data_encoded.to_csv(resultfile_encoded, sep=',', header=True, index=False, encoding='utf_8_sig')
#print('data_encoded:\n', data_encoded)


enc = LeaveOneOutEncoder(cols=['Name_of_col','Another_name'])
training_set = enc.fit_transform(X_train, y_train)

